/*
  Name: Client.h
  Copyright:
  Author: Carl Chatfield
  Date: 06/01/08 12:59
  Description: Stores client info as well as threads for each module
*/


//Will be added to config when i figure out how to use it
void* baseIP = (void*)0x763BB8;
void* basePort = (void*)0x763C1C;
short loginPort = 1337;
int offset = 0x70;
void* baseKey = (void*)0x768C7C;
void* baseConnectionStatus = (void*)0x76C2C8;
void* baseSelectedCharacter = (void*)0x76C288;
//End Config

#include "DeadProxyClient.h"
#include "DeadProxyApp.h"

int Client::GetPid()
{
    return cpid;
}

void* Client::GetHandle()
{
    return chandle;
}

bool Client::IsStandAlone()
{
    return standAlone;
}

int Client::GetPort()
{
    return cport;
}

void Client::SetPort(int port)
{
    cport = port;
}

wxString Client::GetCharName()
{
    return CharacterName;
}

void Client::SetCharName(wxString name)
{
    CharacterName = name;
}

Client::Client(int pid, void* handle, int port, wxString name, bool isStandAlone)
{
    cpid = pid;
    cport = port;
    chandle = handle;
    CharacterName = name;
    standAlone = isStandAlone;
    PackLog = new PacketLog();
    logPacketMode = 0;
    LogMessageChannel = -1;
    isSelected = false;
    EvtMutex = new wxMutex;
    EvtMutex->Unlock();
    EvtCondition = new wxCondition(*EvtMutex);
    EvtQueue = new EventQueue();
    EvtHandler = new EventHandler(EvtQueue, EvtMutex, EvtCondition, this);
    EvtHandler->Create();
    EvtHandler->Run();
    
    Network = new ClientNetworkHandler(this);
    
    //Game Stuff
    Map = new GameMap();
    Player = new PlayerInfo();
    VIP = new VIPList();
    Containers = new ContainerManager();
    MLog = new MessageLog();
    Proto = new Protocol(this);
    
//    ChannelLog * test = new ChannelLog("test channel");
//    wxString * testmsgstr = test->AddMessage("Bob", "is your uncle", 1);
//    wxString * channelname = test->GetString();
//    wxMessageBox(*channelname);
//    wxMessageBox(*testmsgstr);
//    wxArrayString * testarrstr = test->GetMessageInfo(0);
//    wxMessageBox(testarrstr->Item(0));
//    wxMessageBox(testarrstr->Item(1));
//    wxMessageBox(testarrstr->Item(2));
//    wxMessageBox(testarrstr->Item(3)); 
    
//    PackQueue = new PacketQueue();
//    SendMutex = new wxMutex();
//    SendCondition = new wxCondition(*SendMutex);
//    PacketMutex = new wxMutex();
//    PacketCondition = new wxCondition(*PacketMutex);
//    SndQueue = new SendQueue(PackQueue, SendCondition, PacketCondition, ToServerSocket);
//    SndQueue->Create();
//    SndQueue->Run();
    
    if(!standAlone)
    {
        RW = new TibiaRW(chandle);
        void* IPAdd = baseIP;
        void* portAdd = basePort;
        for(int i = 0; i < 10; i++)
        {
             RW->Write(IPAdd, (void*)"127.0.0.1", 10);
             RW->Write(portAdd, &loginPort, 2);
             IPAdd = (void*)((int)IPAdd + offset);
             portAdd = (void*)((int)portAdd + offset);
        }
    } else {
        //make up a key
    }
}

Client::~Client()
{
    delete RW;
    delete Network;
    delete PackLog;
    delete pCharacterList;
}
    
char * Client::GetKey()
{
    RW->Read(baseKey, key, 16);
    return key;
}

int Client::GetConnectionStatus()
{
    int ret = 0;
    RW->Read(baseConnectionStatus, (void*)&ret, 4);
    return ret;
}

void Client::ParseLoginPacket(ClientEvent * evt)
{
    ClientEvent * sendevt = new ClientEvent(CE_PACKET);
    PacketBuffer * packet = ((PacketBuffer*)evt->GetParam3());
    if(evt->GetParam1() == 0)
    {
        if(logPacketMode == 1 || logPacketMode == 3)
        {
            if(isSelected)
            {
                app->AddPacketToBox(PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 0));
            } else {
                PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 0);
            }
        }
        sendevt->SetParam1(2);
    } else {
        packet->SetKey((unsigned char*)key);
        packet->Decrypt();
        packet->ParseLogin(&pCharacterList);
        if(logPacketMode == 2 || logPacketMode == 3)
        {
            if(isSelected)
            {
                app->AddPacketToBox(PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 1));
            } else {
                PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 1);
            }
        }
        packet->Encrypt();
        sendevt->SetParam1(3);
    }
    sendevt->SetParam3(evt->GetParam3());
    PostEvent(sendevt);
}

void Client::ParseGamePacket(ClientEvent * evt)
{
    ClientEvent * sendevt = new ClientEvent(CE_PACKET);
    PacketBuffer * packet = ((PacketBuffer*)evt->GetParam3());
    if(evt->GetParam1() == 0)
    {
        packet->SetKey((unsigned char*)key);
        packet->Decrypt();
        if(logPacketMode == 1 || logPacketMode == 3)
        {
            if(isSelected)
            {
                app->AddPacketToBox(PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 0));
            } else {
                PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 0);
            }
        }
        packet->Encrypt();
        sendevt->SetParam1(2);
    } else {
        packet->SetKey((unsigned char*)key);
        packet->Decrypt();
        if(packet->GetLength() > 1000)
        {
            FILE * f;
            f = fopen("testpacket.bin", "wb");
            fwrite((const void*)packet->GetBuffer(), 1, packet->GetLength(), f);
            fclose(f);
        }
        if(logPacketMode == 2 || logPacketMode == 3)
        {
            if(isSelected)
            {
                app->AddPacketToBox(PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 1));
            } else {
                PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 1);
            }
        }
        packet->Encrypt();
        sendevt->SetParam1(3);
    }
    sendevt->SetParam3(evt->GetParam3());
    PostEvent(sendevt);
}

void Client::GetConnectingCharacterInfo(int * ip, short * port)
{
    int CharacterNumber;
    RW->Read(baseSelectedCharacter, &CharacterNumber, 4);
    *ip = pCharacterList->CharList[CharacterNumber].IP;
    *port = pCharacterList->CharList[CharacterNumber].port;
}

void Client::SetLogPacketMode(ClientEvent * evt)
{
    logPacketMode = evt->GetParam1();
}

int Client::GetLogPacketMode()
{
    return logPacketMode;
}

wxString * Client::GetPacketString(ClientEvent * evt)
{
    return PackLog->GetPacketString(evt->GetParam1());
}

void Client::ParseSendPacket(PacketBuffer * packet)
{
    packet->SetKey((unsigned char*)key);
    packet->Decrypt();
    wxString output;
    if(logPacketMode == 1 || logPacketMode == 3)
    {
        if(isSelected)
        {
            app->AddPacketToBox(PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 0));
        } else {
            delete PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 0); //remember if something goes wrong
        }
    }
    packet->Encrypt();
}

void Client::ParseRecvPacket(PacketBuffer * packet)
{
    packet->SetKey((unsigned char*)key);
    packet->Decrypt();
    if(logPacketMode == 2 || logPacketMode == 3)
    {
        if(isSelected)
        {
            app->AddPacketToBox(PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 1));
        } else {
            delete PackLog->AddPacket(packet->GetCopy(), packet->GetLength(), 1); //remember if something goes wrong
        }
    }
    packet->Encrypt();
}

void Client::ClearPacketLog()
{
    PackLog->ClearLog();
}

wxArrayString * Client::GetPacketListBoxArray()
{
    return PackLog->GetListBoxArray();
}

void Client::SetSelected(ClientEvent * evt)
{
    //wxString out;
    //out.Printf("%i", cpid);
    if(evt->GetParam1())
    {
        //wxMessageBox(out + "im alive");
        isSelected = true;
        InitSelectInfo * ISI = new InitSelectInfo;
        ISI->CharName = &CharacterName;
        ISI->WorldName = &WorldName;
        ISI->pid = cpid;
        ISI->port = cport;
        ISI->IsStandAlone = standAlone;
        ISI->LogPacketMode = logPacketMode;
        ISI->PacketSelectListBoxArray = GetPacketListBoxArray();
        app->InitClientSelectInfo(ISI);
        //wxMessageBox(out + "staying alive");
    } else {
        //wxMessageBox(out + "im dead");
        isSelected = false;
    }
}

void Client::PostEvent(ClientEvent* evt)
{
    EvtQueue->AddEvent(evt);
    EvtCondition->Broadcast();
}

void Client::TestFunc()
{
//    Proto->TestMap();
//    wxGUIEvent *UpdateMiniClientEvent = (wxGUIEvent *)wxCreateDynamicObject(wxT("wxGUIEvent"));
//    UpdateMiniClientEvent->SetParam1((int)this);
//    UpdateMiniClientEvent->SetEventType(wxEVT_UPDATE_MINICLIENT);
//    UpdateMiniClientEvent->SetId(wxUPDATE_MINICLIENT_ID);
//    wxPostEvent(app->frame->pMiniClientCanvas, *UpdateMiniClientEvent);
    AddMessage("Rick", "James", 0, 0x04);
    AddMessage("Rick", "Bitch", 0, 0x04);
    AddMessage("Vader", "Luke", 0, 0x04);
    AddMessage("Vader", "I am your father", 0, 0x04);
    OpenChannel("Test Channel", 10);
    AddMessage("SuperMan", "To the rescue", 10, 0x05);
    AddMessage("Villan", "Not So Fast Super Man", 10, 0x05);
}

void Client::SetPacketString(ClientEvent * evt)
{
    app->SetPacketString(PackLog->GetPacketString(evt->GetParam1()));
}

void Client::SetLogMessageChannel(ClientEvent * evt)
{
    LogMessageChannel = evt->GetParam1();
    wxArrayString * MessageArray = MLog->GetMessageBoxArray(evt->GetParam1());
    app->SetMessageBoxArray(MessageArray);
}

void Client::SetMessageInfo(ClientEvent * evt)
{
    wxArrayString * Info = MLog->GetMessageInfo(evt->GetParam1(), evt->GetParam2());
    app->SetMessageInfo(Info);
}

void Client::SetMessageBoxArray(ClientEvent * evt)
{
    wxArrayString * MessageArray = MLog->GetMessageBoxArray(evt->GetParam1());
    app->SetMessageBoxArray(MessageArray);
}

void Client::AddMessage(char * sender, char * text, int channelid, int type)
{
    wxString * Sender = new wxString(sender);
    wxString * Text = new wxString(text);
    delete sender;
    delete text;
    MessageLog::AddMessageStruct * Message = MLog->AddMessage(Sender, Text, channelid, type);
    if(LogMessageChannel == Message->Channel)
    {
        app->AddMessageToBox(Message->MessageString);
    } else {
        delete(Message->MessageString);
    }
    if(Message->ChannelName != 0)
    {
        app->AddChannelToBox(Message->ChannelName);
    }
}

void Client::ClearMessageLog(ClientEvent * evt)
{
    app->ClearMessageBox();
    if(evt->GetParam2() == 0) // Clear 1 log
    {
        if(MLog->ClearLog(evt->GetParam1()))
        {
            app->RemoveChannelFromBox(evt->GetParam1());
        }
    }
    if(evt->GetParam2() == 1) // Clear All Logs
    {
        for(int i = MLog->GetCount() - 1; i >= 0; i--)
        {
            if(MLog->ClearLog(i))
            {
                app->RemoveChannelFromBox(i);
            }
        }
    }
}

void Client::OpenChannel(char * channelname, int channelid)
{
    wxString * ChannelName = new wxString(channelname);
    app->AddChannelToBox(MLog->OpenChannel(ChannelName, channelid));
}

void Client::EventParser(ClientEvent * evt)
{
    int id = evt->GetID();
    switch(id)
    {
        case 1:
            TestFunc();
            break;
        case 2:
            wxMessageBox(*evt->GetStr1());
            break;
        case CE_DESTROYSELF:
            delete this;
            break;
        case CE_NETEVENT:
            Network->Message(evt);
            break;
        case CE_SETLOGMODE:
            SetLogPacketMode(evt);
            break;
        case CE_GET_PACKET_STRING:
            SetPacketString(evt);
            break;
        case CE_SET_SELECTED:
            SetSelected(evt);
            break;
        case CE_CLEAR_PACKET_LOG:
            ClearPacketLog();
            break;
        case CE_SET_SELECTED_CHANNEL:
            SetLogMessageChannel(evt);
            break;
        case CE_GET_MESSAGE_INFO:
            SetMessageInfo(evt);
            break;
        case CE_GET_MESSAGE_ARRAY:
            SetMessageBoxArray(evt);
            break;
        case CE_CLEAR_MESSAGE_LOG:
            ClearMessageLog(evt);
            break;
        case CE_PACKET:
            switch(evt->GetParam1())
            {
                case 0:
                    switch(evt->GetParam2())
                    {
                        case 0:
                            ParseLoginPacket(evt);
                            break;
                        case 1:
                            ParseGamePacket(evt);
                            break;
                    }
                    break;
                case 1:
                    switch(evt->GetParam2())
                    {
                        case 0:
                            ParseLoginPacket(evt);
                            break;
                        case 1:
                            ParseGamePacket(evt);
                            break;
                    }
                    break;
                case 2:
                    Network->SendToServer((PacketBuffer*)evt->GetParam3());
                    break;
                case 3:
                    Network->SendToClient((PacketBuffer*)evt->GetParam3());
                    break;
            }
            break;
    }
}
